import { EventToPlayerCacheService } from '../../event-to-player/event-to-player.cache.service';
import { StageService } from 'src/modules/stage/stage.service';
import { Injectable } from '@nestjs/common';
import { EventToPlayerService } from 'src/modules/event-to-player/event-to-player.service';
import { MatchService } from 'src/modules/match/match.service';
import { GameService } from 'src/modules/game/game.service';
import { GroupService } from 'src/modules/group/group.service';
import { GroupCacheService } from 'src/modules/group/group.cache.service';
import { StageCacheService } from 'src/modules/stage/stage.cache.service';
import { MatchCacheService } from 'src/modules/match/match.cache.service';
import { Stage } from 'src/modules/stage/entities/stage.entity';

@Injectable()
export class StageDetailService {
  constructor(
    private readonly stageService: StageService,
    private readonly groupService: GroupService,
    private readonly eventToPlayerService: EventToPlayerService,
    private readonly matchService: MatchService,
    private readonly gameService: GameService,
    private readonly stageCacheService: StageCacheService,
    private readonly matchCacheService: MatchCacheService,
    private readonly groupCacheService: GroupCacheService,
    private readonly eventToPlayerCacheService: EventToPlayerCacheService,
  ) {}
  async findStage(stageId: number) {
    const stageIndCache = await this.stageCacheService.getStage(stageId);
    if (stageIndCache) {
      console.log('stageIndCache');
      return stageIndCache;
    }
    const stageInDb = await this.stageService.getByIdWithGroupDetails(stageId);
    if (stageInDb) {
      await this.stageCacheService.setStage(stageInDb);
    }
    return stageInDb;
  }
  async listMatchByStageId(stageId: number) {
    const matchCache = await this.matchCacheService.getListByStageId(stageId);
    if (matchCache) {
      return matchCache;
    }
    const matchInDb = await this.matchService.getByStageId(stageId);
    if (matchInDb) {
      await this.matchCacheService.setListByStageId(stageId, matchInDb);
    }
    return matchInDb;
  }
  async listE2PByEventId(eventId: number) {
    const e2pCache =
      await this.eventToPlayerCacheService.getListByEventId(eventId);
    if (e2pCache) {
      return e2pCache;
    }
    const e2pInDb = await this.eventToPlayerService.findByEventId(eventId);
    if (e2pInDb) {
      await this.eventToPlayerCacheService.setListByEventId(eventId, e2pInDb);
    }
    return e2pInDb;
  }

  async getStageDetailWithPlayerInfo(stageId: number): Promise<Stage> {
    const stageInfo = await this.getStageDetail(stageId);
    const { eventId, groups } = stageInfo;
    const eventToPlayers = await this.listE2PByEventId(eventId);
    groups.forEach((group) => {
      const { matchInfos, groupPlayerScores } = group;
      //补充mathc 和 game 的player 信息
      const playerMap = new Map();
      eventToPlayers.forEach((player) => {
        playerMap.set(player.id, player);
      });
      matchInfos.forEach((match) => {
        match.homePlayer = playerMap.get(match.homePlayerId);
        match.awayPlayer = playerMap.get(match.awayPlayerId);
        match.winner = playerMap.get(match.winnerId);
        if (match.games) {
          match.games.forEach((game) => {
            game.homePlayer = playerMap.get(game.homePlayerId);
            game.awayPlayer = playerMap.get(game.awayPlayerId);
          });
        }
        if (match.subMatchInfos) {
          match.subMatchInfos.forEach((subMatch) => {
            subMatch.homePlayer = playerMap.get(subMatch.homePlayerId);
            subMatch.awayPlayer = playerMap.get(subMatch.awayPlayerId);
            subMatch.winner = playerMap.get(subMatch.winnerId);
            if (subMatch.games) {
              subMatch.games.forEach((game) => {
                game.homePlayer = playerMap.get(game.homePlayerId);
                game.awayPlayer = playerMap.get(game.awayPlayerId);
              });
            }
          });
        }
      });
      // 补充groupPlayerScores 的player 信息
      groupPlayerScores.forEach((groupPlayerScore) => {
        groupPlayerScore.player = playerMap.get(groupPlayerScore.playerId);
      });
    });

    return stageInfo;
  }
  async getStageDetail(stageId: number): Promise<Stage> {
    // 1. 并发执行多个小查询
    console.time('getStageMatches1');
    const [stage, matchInfos] = await Promise.all([
      this.findStage(stageId),
      this.listMatchByStageId(stageId),
    ]);
    console.timeEnd('getStageMatches1');
    // 2. 组装数据
    if (!stage) {
      return null;
    }
    console.time('getStageMatches2');
    // const { eventId } = stage;
    const matchIds = matchInfos.map((v) => v.id);
    const [games] = await Promise.all([
      // this.listE2PByEventId(eventId),
      this.gameService.findInMatchIds(matchIds),
    ]);
    console.timeEnd('getStageMatches2');

    console.time('getStageMatches3');
    // 创建比赛映射，便于快速查找
    const matchMap = new Map();
    matchInfos.forEach((match) => {
      matchMap.set(match.id, match);
      match.games = [];
      match.subMatchInfos = [];
    });

    // 处理submatchInfo的关联
    matchInfos.forEach((match) => {
      if (match.subMatchId) {
        const parentMatch = matchMap.get(match.subMatchId);
        if (parentMatch) {
          parentMatch.subMatchInfos = parentMatch.subMatchInfos || [];
          parentMatch.subMatchInfos.push(match);
        }
      }
    });
    matchInfos.filter((match) => {
      return match.subMatchId === null;
    });

    // 将局信息关联到对应的比赛
    games.forEach((game) => {
      const match = matchMap.get(game.matchId);
      if (match) {
        match.games.push(game);
      }
    });
    // 将比赛信息关联到对应的分组
    const groupMap = new Map();
    stage.groups.forEach((group) => {
      groupMap.set(group.id, group);
      // 初始化分组的matchInfos数组
      if (!group.matchInfos) {
        group.matchInfos = [];
      }
    });

    matchInfos.forEach((match) => {
      if (match.groupId) {
        const group = groupMap.get(match.groupId);
        if (group) {
          group.matchInfos.push(match);
        }
      }
    });
    console.timeEnd('getStageMatches3');

    return stage;
  }
}
